home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
tkern10.zip
/
SRC\WINDOW.C
< prev
next >
Wrap
Text File
|
1994-05-16
|
30KB
|
1,401 lines
/*
* This file forms part of "TKERN" - "Troy's Kernel for Windows".
*
* Copyright (C) 1994 Troy Rollo <troy@cbme.unsw.EDU.AU>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <windows.h>
#include <windowsx.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/tfile.h>
#include <sys/tdevice.h>
#include <sys/tkwin.h>
void far tkern_deliver_signal( int nDevice,
int nFile,
int nSignal);
static BOOL bRegistered = 0;
static int iDevice;
extern HINSTANCE hInstance;
extern int nError;
extern void UnlockManager(void);
extern void LockManager(void);
extern void FlushMessages(void);
extern void tkern_wakeup_call(void);
static int window_destroy(HWND hWnd);
#define SC_COPY 5000
#define SC_PASTE 5001
#define SC_COPYPASTE 5002
#define DEF_MAXLINES 100
#define DEF_SCROLLLINES 5
struct line
{
struct line *plNext;
struct line *plPrev;
char *pchLine;
};
struct per_window
{
struct line *pw_head;
struct line *pw_tail;
struct line *pw_inhead;
struct line *pw_intail;
struct line *pw_history;
struct line *pw_hishead;
struct line *pw_histail;
int nUnscrolledLines;
int nHistory;
int nHistMax;
int nScrollLines;
int nLines; /* Counter so we can keep the list reasonable */
int nLinesMax;
int cxChar;
int cyChar;
int nScrollPos;
HWND hEdit;
int xEditStart;
POINT ptMarkStart;
POINT ptMarkEnd;
BOOL bMarkValid;
BOOL bHaveMouse;
BOOL bProgramClosed;
};
#define ENTER_HIT WM_USER + 1000
#define UP_HIT WM_USER + 1001
#define DOWN_HIT WM_USER + 1002
WNDPROC NormalEditWndProc = 0;
FARPROC FakeEditThunk = 0;
int far pascal _export
FakeEditWndProc( HWND hWnd,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
if (wMsg == WM_KEYDOWN)
{
if (wParam == VK_UP)
{
SendMessage(GetParent(hWnd), UP_HIT, 0, 0);
return 0;
}
else if (wParam == VK_DOWN)
{
SendMessage(GetParent(hWnd), DOWN_HIT, 0, 0);
return 0;
}
}
if (wMsg == WM_CHAR)
{
if (wParam == VK_RETURN)
{
SendMessage(GetParent(hWnd), ENTER_HIT, 0, 0);
return 0;
}
else if (wParam == VK_TAB)
{
SendMessage(hWnd, EM_REPLACESEL, 0, (long) "\t");
return 0;
}
else if (wParam == 3)
{
tkern_deliver_signal(iDevice,
(int) GetParent(hWnd),
2);
return 0;
}
}
return (*NormalEditWndProc)(hWnd, wMsg, wParam, lParam);
}
static void
MoveMark(struct per_window *pw,
int nLines)
{
if (pw->bMarkValid)
{
pw->ptMarkStart.y += nLines;
pw->ptMarkEnd.y += nLines;
}
}
static void
screen_to_row( HWND hWnd,
struct per_window *pw,
int x,
int y,
int *xOut,
int *yOut)
{
RECT rcClient;
int cyLastRow;
struct line *pl;
int i, j;
GetClientRect(hWnd, &rcClient);
y = rcClient.bottom - y;
cyLastRow = pw->cyChar + pw->cyChar / 5 * 2;
if (y < cyLastRow)
{
*yOut = 0;
}
else
{
*yOut = (y - cyLastRow) / pw->cyChar + 1;
}
if (*yOut > 0)
*yOut += pw->nScrollPos;
for (i = *yOut, pl = pw->pw_tail;
i && pl;
i--, pl = pl->plPrev);
if (!pl || !pl->pchLine)
{
*xOut = 0;
return;
}
x = x / pw->cxChar;
for (i = j = 0; x > j && pl->pchLine[i]; i++)
{
if (pl->pchLine[i] == '\t')
j += 8 - j % 8;
else
j++;
}
*xOut = i;
}
static void
RedrawPoints( HWND hWnd,
struct per_window *pw,
POINT ptStart_,
POINT ptEnd_)
{
POINT ptStart, ptEnd;
RECT rcRedraw;
if (ptStart_.y > ptEnd_.y)
{
ptStart = ptStart_;
ptEnd = ptEnd_;
}
else if (ptStart_.y < ptEnd_.y)
{
ptStart = ptEnd_;
ptEnd = ptStart_;
}
else if (ptStart_.x < ptEnd_.x)
{
ptStart = ptStart_;
ptEnd = ptEnd_;
}
else
{
ptStart = ptEnd_;
ptEnd = ptStart_;
}
if (ptEnd.y > 0)
{
ptEnd.y -= pw->nScrollPos;
if (ptEnd.y < 0)
ptEnd.y = 0;
}
if (ptStart.y > 0)
{
ptStart.y -= pw->nScrollPos;
if (ptStart.y < 1)
ptStart.y = 1;
}
if (ptStart.y < ptEnd.y)
return;
GetClientRect(hWnd, &rcRedraw);
rcRedraw.top = rcRedraw.bottom - pw->cyChar * (ptStart.y + 1) - pw->cyChar / 5 * 2;
if (ptEnd.y)
rcRedraw.bottom -= pw->cyChar * ptEnd.y + pw->cyChar / 5 * 2;
InvalidateRect(hWnd, &rcRedraw, TRUE);
}
static void
MouseDown( HWND hWnd,
struct per_window *pw,
int x,
int y)
{
if (pw->bMarkValid)
{
pw->bMarkValid = FALSE;
RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
}
screen_to_row(hWnd, pw, x, y, &pw->ptMarkStart.x, &pw->ptMarkStart.y);
pw->ptMarkEnd = pw->ptMarkStart;
RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
SetCapture(hWnd);
pw->bHaveMouse = TRUE;
pw->bMarkValid = TRUE;
}
static void
MouseMove( HWND hWnd,
struct per_window *pw,
int x,
int y)
{
POINT ptTemp;
ptTemp = pw->ptMarkEnd;
screen_to_row(hWnd, pw, x, y, &pw->ptMarkEnd.x, &pw->ptMarkEnd.y);
RedrawPoints(hWnd, pw, ptTemp, pw->ptMarkEnd);
}
static void
MouseUp(struct per_window *pw)
{
ReleaseCapture();
pw->bHaveMouse = FALSE;
}
static void
get_mark_coordinates( struct per_window *pw,
POINT *ptOne,
POINT *ptTwo)
{
if (pw->ptMarkStart.y > pw->ptMarkEnd.y)
{
*ptOne = pw->ptMarkStart;
*ptTwo = pw->ptMarkEnd;
}
else if (pw->ptMarkStart.y < pw->ptMarkEnd.y)
{
*ptOne = pw->ptMarkEnd;
*ptTwo = pw->ptMarkStart;
}
else if (pw->ptMarkStart.x < pw->ptMarkEnd.x)
{
*ptOne = pw->ptMarkStart;
*ptTwo = pw->ptMarkEnd;
}
else
{
*ptOne = pw->ptMarkEnd;
*ptTwo = pw->ptMarkStart;
}
}
static int
is_in_mark( int iRow,
struct per_window *pw,
int *iMarkBoundary1,
int *iMarkBoundary2)
{
POINT ptStart, ptEnd;
if (!pw->bMarkValid)
return 0;
get_mark_coordinates(pw, &ptStart, &ptEnd);
if (ptStart.y > ptEnd.y)
{
if (ptEnd.y > iRow ||
ptStart.y < iRow)
return 0;
if (ptStart.y == iRow)
{
*iMarkBoundary1 = ptStart.x;
return 1;
}
if (ptEnd.y == iRow)
{
*iMarkBoundary1 = ptEnd.x;
return 2;
}
return 3;
}
else if (ptStart.y == iRow)
{
*iMarkBoundary1 = ptStart.x;
*iMarkBoundary2 = ptEnd.x;
return 4;
}
else
{
return 0;
}
}
static void
PlaceEdit( HWND hWnd,
struct per_window *pw)
{
RECT rcLoc;
GetClientRect(hWnd, &rcLoc);
rcLoc.left = pw->xEditStart;
rcLoc.top = rcLoc.bottom - pw->cyChar - pw->cyChar / 5;
if (pw->hEdit)
{
MoveWindow(pw->hEdit,
rcLoc.left, rcLoc.top,
rcLoc.right - rcLoc.left + 1,
rcLoc.bottom - rcLoc.top + 1,
TRUE);
}
else
{
pw->hEdit = CreateWindow( "EDIT",
"",
WS_VISIBLE |
WS_CHILD |
ES_AUTOHSCROLL |
ES_LEFT,
rcLoc.left,
rcLoc.top,
rcLoc.right - rcLoc.left,
rcLoc.bottom - rcLoc.top,
hWnd,
(HMENU) 100,
hInstance,
0
);
if (!NormalEditWndProc)
{
NormalEditWndProc = (WNDPROC)
GetWindowLong(pw->hEdit, GWL_WNDPROC);
}
if (!FakeEditThunk)
{
FakeEditThunk = MakeProcInstance((FARPROC) FakeEditWndProc, hInstance);
}
SetWindowLong(pw->hEdit, GWL_WNDPROC, (long) FakeEditThunk);
}
}
static void
PaintWindow( HWND hWnd,
struct per_window *pw)
{
PAINTSTRUCT ps;
TEXTMETRIC tm;
LOGFONT lf;
int cyChar;
int cyInch;
int yLocation;
int nRows;
RECT rcClient;
HFONT hFont, hOldFont;
int iRow, iTemp, iTotal;
struct line *pl;
LONG xExtent, xExtent2;
BOOL bBottom = TRUE;
int iMarkBoundary1, iMarkBoundary2;
COLORREF crBG, crFG, crFGHigh, crBGHigh;
crFG = GetSysColor(COLOR_WINDOWTEXT);
crBG = GetSysColor(COLOR_WINDOW);
crFGHigh = GetSysColor(COLOR_HIGHLIGHTTEXT);
crBGHigh = GetSysColor(COLOR_HIGHLIGHT);
if (pw->nUnscrolledLines)
{
if (!pw->nScrollPos)
ScrollWindow(hWnd, 0, -pw->nUnscrolledLines * pw->cyChar, 0, 0);
pw->nUnscrolledLines = 0;
PlaceEdit(hWnd, pw);
UpdateWindow(hWnd);
}
BeginPaint(hWnd, &ps);
cyInch = GetDeviceCaps(ps.hdc, LOGPIXELSY);
memset(&lf, 0, sizeof(lf));
lf.lfHeight = MulDiv(cyInch, 12, 72);
strcpy(lf.lfFaceName, "System");
lf.lfPitchAndFamily = FIXED_PITCH;
hFont = CreateFontIndirect(&lf);
hOldFont = SelectFont(ps.hdc, hFont);
GetTextMetrics(ps.hdc, &tm);
cyChar = tm.tmHeight + tm.tmExternalLeading;
GetClientRect(hWnd, &rcClient);
pw->cxChar = tm.tmAveCharWidth;
pw->cyChar = cyChar;
pl = pw->pw_tail;
if (pw->pw_tail->pchLine)
xExtent = GetTabbedTextExtent(ps.hdc,
pl->pchLine,
strlen(pl->pchLine),
0, 0);
else
xExtent = 0;
pw->xEditStart = LOWORD(xExtent);
PlaceEdit(hWnd, pw);
nRows = (rcClient.bottom - ps.rcPaint.top) / cyChar + 1;
for (iRow = 0, iTotal = 0, pl = pw->pw_tail,
yLocation = rcClient.bottom - cyChar;
pl && iTotal < nRows;
iRow++, iTotal++, pl = pl->plPrev)
{
if (iRow == 1 && pw->nScrollPos)
{
for (iTemp = 0; iTemp < pw->nScrollPos && pl; iTemp++, pl = pl->plPrev, iRow++);
if (!pl)
break;
}
if (bBottom)
{
yLocation -= cyChar / 5;
}
if (pl->pchLine)
{
switch(is_in_mark(iRow, pw, &iMarkBoundary1, &iMarkBoundary2))
{
case 0: /* Not in a marked area */
SetTextColor(ps.hdc, crFG);
SetBkColor(ps.hdc, crBG);
TabbedTextOut(ps.hdc, 0, yLocation,
pl->pchLine, strlen(pl->pchLine),
0, 0, 0);
break;
case 1: /* First line in a marked area */
SetTextColor(ps.hdc, crFG);
SetBkColor(ps.hdc, crBG);
TabbedTextOut(ps.hdc, 0, yLocation,
pl->pchLine, iMarkBoundary1,
0, 0, 0);
xExtent = GetTabbedTextExtent(ps.hdc,
pl->pchLine,
iMarkBoundary1,
0, 0);
SetTextColor(ps.hdc, crFGHigh);
SetBkColor(ps.hdc, crBGHigh);
TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
pl->pchLine + iMarkBoundary1,
strlen(pl->pchLine) - iMarkBoundary1,
0, 0, 0);
break;
case 2: /* Last line in a marked area */
SetTextColor(ps.hdc, crFGHigh);
SetBkColor(ps.hdc, crBGHigh);
TabbedTextOut(ps.hdc, 0, yLocation,
pl->pchLine, iMarkBoundary1,
0, 0, 0);
xExtent = GetTabbedTextExtent(ps.hdc,
pl->pchLine,
iMarkBoundary1,
0, 0);
SetTextColor(ps.hdc, crFG);
SetBkColor(ps.hdc, crBG);
TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
pl->pchLine + iMarkBoundary1,
strlen(pl->pchLine) - iMarkBoundary1,
0, 0, 0);
break;
case 3: /* Entire line is in a marked area */
SetTextColor(ps.hdc, crFGHigh);
SetBkColor(ps.hdc, crBGHigh);
TabbedTextOut(ps.hdc, 0, yLocation,
pl->pchLine, strlen(pl->pchLine),
0, 0, 0);
break;
case 4: /* Both first and last line in marked area */
SetTextColor(ps.hdc, crFG);
SetBkColor(ps.hdc, crBG);
TabbedTextOut(ps.hdc, 0, yLocation,
pl->pchLine, iMarkBoundary1,
0, 0, 0);
xExtent = GetTabbedTextExtent(ps.hdc,
pl->pchLine,
iMarkBoundary1,
0, 0);
SetTextColor(ps.hdc, crFGHigh);
SetBkColor(ps.hdc, crBGHigh);
TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
pl->pchLine + iMarkBoundary1,
iMarkBoundary2 - iMarkBoundary1,
0, 0, 0);
xExtent2 = GetTabbedTextExtent(ps.hdc,
pl->pchLine + iMarkBoundary1,
iMarkBoundary2 - iMarkBoundary1,
0, 0);
SetTextColor(ps.hdc, crFG);
SetBkColor(ps.hdc, crBG);
TabbedTextOut(ps.hdc, LOWORD(xExtent) + LOWORD(xExtent2),
yLocation,
pl->pchLine + iMarkBoundary2,
strlen(pl->pchLine) - iMarkBoundary2,
0, 0, 0);
break;
}
}
yLocation -= cyChar;
if (bBottom)
{
yLocation -= cyChar / 5;
bBottom = FALSE;
}
}
SelectFont(ps.hdc, hOldFont);
DeleteFont(hFont);
EndPaint(hWnd, &ps);
}
void
GotLine(struct per_window *pw)
{
struct line *plTemp, *plNew;
char *pchData;
int nLen;
pw->pw_history = 0;
nLen = GetWindowTextLength(pw->hEdit);
/* Once for the input queue */
pchData = (char *) malloc(nLen + 1);
GetWindowText(pw->hEdit, pchData, nLen + 1);
pchData[nLen] = 0;
plNew = (struct line *) malloc(sizeof(struct line));
plNew->plNext = 0;
plNew->plPrev = pw->pw_intail;
plNew->pchLine = pchData;
if (pw->pw_intail)
pw->pw_intail->plNext = plNew;
else
pw->pw_inhead = plNew;
pw->pw_intail = plNew;
/* Once for the history list */
pchData = (char *) malloc(nLen + 1);
GetWindowText(pw->hEdit, pchData, nLen + 1);
pchData[nLen] = 0;
plNew = (struct line *) malloc(sizeof(struct line));
plNew->plNext = 0;
plNew->plPrev = pw->pw_histail;
plNew->pchLine = pchData;
if (pw->pw_histail)
pw->pw_histail->plNext = plNew;
else
pw->pw_hishead = plNew;
pw->pw_histail = plNew;
if (pw->nHistory >= pw->nHistMax)
{
plTemp = pw->pw_hishead;
pw->pw_hishead = plTemp->plNext;
pw->pw_hishead->plPrev = 0;
if (plTemp->pchLine)
free(plTemp->pchLine);
free(plTemp);
}
else
{
pw->nHistory++;
}
SetWindowText(pw->hEdit, "");
tkern_wakeup_call();
}
static BOOL
CopyText( HWND hWnd,
struct per_window *pw)
{
POINT ptStart;
POINT ptEnd;
int i;
int j;
int nBytes;
struct line *pl, *plSaved;
HGLOBAL hmem;
char *pchData;
if (!pw->bMarkValid)
{
MessageBeep(MB_ICONSTOP);
return FALSE;
}
if (!OpenClipboard(hWnd))
{
MessageBeep(MB_ICONEXCLAMATION);
return FALSE;
}
EmptyClipboard();
/* The clipboard wants CRLF separated lines. Figure out
* how many characters it will be.
*/
get_mark_coordinates(pw, &ptStart, &ptEnd);
for (pl = pw->pw_tail, i = 0; pl && i < ptStart.y; pl = pl->plPrev, i++);
plSaved = pl;
nBytes = 1; /* For the terminating NUL (not NULL) byte */
while (i >= ptEnd.y)
{
nBytes += (pl->pchLine ? strlen(pl->pchLine) : 0);
if (ptEnd.y == i)
nBytes -= (pl->pchLine ? (strlen(pl->pchLine) - ptEnd.x) : 0);
else
nBytes += 2;
if (ptStart.y == i)
nBytes -= ptStart.x;
i--;
pl = pl->plNext;
}
hmem = GlobalAlloc(GMEM_MOVEABLE, nBytes);
pchData = GlobalLock(hmem);
i = ptStart.y;
pl = plSaved;
while (i >= ptEnd.y)
{
if (i == ptStart.y)
j = ptStart.x;
else
j = 0;
if (i == ptEnd.y)
{
if (pl->pchLine)
{
strncpy(pchData, pl->pchLine + j, ptEnd.x - j);
pchData += ptEnd.x - j;
}
}
else
{
if (pl->pchLine)
{
strcpy(pchData, pl->pchLine + j);
pchData += strlen(pchData);
}
*pchData++ = '\r';
*pchData++ = '\n';
}
i--;
pl = pl->plNext;
}
*pchData = '\0';
GlobalUnlock(hmem);
SetClipboardData(CF_TEXT, hmem);
CloseClipboard();
return TRUE;
}
static void
PasteText( HWND hWnd,
struct per_window *pw)
{
HGLOBAL hmem;
char *pchData;
char *pchEOL;
char *pchRemainder = 0;
char *pchNow;
char *pchTemp;
int nTemp;
int iRemainder;
DWORD dwSelection;
if (!OpenClipboard(hWnd))
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
hmem = GetClipboardData(CF_TEXT);
if (!hmem)
{
MessageBeep(MB_ICONSTOP);
return;
}
pchData = GlobalLock(hmem);
while ((pchEOL = strchr(pchData, '\r')) != 0)
{
pchNow = malloc(pchEOL - pchData + 1);
strncpy(pchNow, pchData, pchEOL - pchData);
pchNow[pchEOL - pchData] = 0;
SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchNow);
free(pchNow);
/* Remove the tail end of the line. This will get stuck
* back in once we get to the end of all this.
*
* Note that if we have done this once already, we know
* the selection is theoretically at the end of the window.
*/
if (!pchRemainder)
{
dwSelection = SendMessage(pw->hEdit, EM_GETSEL, 0, 0);
iRemainder = HIWORD(dwSelection);
nTemp = GetWindowTextLength(pw->hEdit);
pchTemp = malloc(nTemp + 1);
GetWindowText(pw->hEdit, pchTemp, nTemp + 1);
pchRemainder = malloc(nTemp - iRemainder + 1);
strcpy(pchRemainder, pchTemp + iRemainder);
pchTemp[iRemainder] = 0;
SetWindowText(pw->hEdit, pchTemp);
free(pchTemp);
}
GotLine(pw);
pchData = pchEOL + 1;
if (*pchData == '\n')
pchData++;
}
SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchData);
if (pchRemainder)
{
iRemainder = GetWindowTextLength(pw->hEdit);
SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchRemainder);
SendMessage(pw->hEdit, EM_SETSEL, TRUE, MAKELPARAM(iRemainder, iRemainder));
free(pchRemainder);
}
}
static void
Scroll( HWND hWnd,
struct per_window *pw,
WPARAM wParam,
int nPos)
{
int nNewPos;
RECT rcScroll;
int nRows;
nNewPos = pw->nScrollPos;
GetClientRect(hWnd, &rcScroll);
rcScroll.bottom -= pw->cyChar + pw->cyChar / 5;
nRows = rcScroll.bottom / pw->cyChar - 1;
switch(wParam)
{
case SB_BOTTOM:
nNewPos = 0;
break;
case SB_LINEDOWN:
nNewPos--;
break;
case SB_LINEUP:
nNewPos++;
break;
case SB_PAGEUP:
nNewPos += nRows - 1;
break;
case SB_PAGEDOWN:
nNewPos -= nRows - 1;
break;
case SB_THUMBPOSITION:
nNewPos = nPos;
break;
case SB_TOP:
nNewPos = pw->nLines;
break;
}
if (nNewPos > pw->nLines)
nNewPos = pw->nLines;
if (nNewPos < 0)
nNewPos = 0;
SetScrollPos(hWnd, SB_VERT, pw->nLines - nNewPos, TRUE);
if (abs(pw->nScrollPos - nNewPos) >= nRows)
InvalidateRect(hWnd, &rcScroll, TRUE);
else
ScrollWindow(hWnd, 0,
pw->cyChar * (nNewPos - pw->nScrollPos),
&rcScroll, &rcScroll);
pw->nScrollPos = nNewPos;
if (nNewPos > 0)
pw->nUnscrolledLines = 0;
}
LRESULT CALLBACK _export
WindowProc( HWND hWnd,
UINT wMsg,
WPARAM wParam,
LPARAM lParam)
{
struct per_window *pw;
PAINTSTRUCT ps;
TEXTMETRIC tm;
HDC hdc;
pw = (struct per_window *) GetWindowLong(hWnd, 0);
switch(wMsg)
{
case WM_CREATE:
hdc = GetDC(hWnd);
GetTextMetrics(hdc, &tm);
ReleaseDC(hWnd, hdc);
pw = (struct per_window *) malloc(sizeof(struct per_window));
memset(pw, 0, sizeof(struct per_window));
pw->cxChar = tm.tmAveCharWidth;
pw->cyChar = tm.tmHeight + tm.tmExternalLeading;
pw->pw_head = (struct line *) malloc(sizeof(struct line));
pw->pw_tail = pw->pw_head;
pw->pw_head->plNext = pw->pw_head->plPrev = 0;
pw->pw_head->pchLine = 0;
pw->nHistMax = 20;
pw->nScrollLines = DEF_SCROLLLINES;
pw->nLinesMax = DEF_MAXLINES;
pw->nLines = 1;
pw->nUnscrolledLines = 0;
SetWindowLong(hWnd, 0, (long) pw);
PlaceEdit(hWnd, pw);
break;
case WM_CLOSE:
if (!pw->bProgramClosed)
{
MessageBeep(MB_ICONSTOP);
}
else
{
window_destroy(hWnd);
}
return 0;
case WM_PAINT:
PaintWindow(hWnd, pw);
return 0;
case WM_SETFOCUS:
SetFocus(pw->hEdit);
return 0;
case WM_LBUTTONDOWN:
MouseDown(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
break;
case WM_MOUSEMOVE:
if (pw->bHaveMouse)
MouseMove(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
break;
case WM_LBUTTONUP:
if (pw->bHaveMouse)
MouseUp(pw);
break;
case WM_VSCROLL:
Scroll(hWnd, pw, wParam, LOWORD(lParam));
break;
case WM_SYSCOMMAND:
switch(wParam)
{
case SC_COPY:
CopyText(hWnd, pw);
break;
case SC_PASTE:
PasteText(hWnd, pw);
break;
case SC_COPYPASTE:
if (CopyText(hWnd, pw))
PasteText(hWnd, pw);
break;
}
break;
case ENTER_HIT:
GotLine(pw);
break;
case UP_HIT:
if (pw->pw_history)
{
if (pw->pw_history->plPrev)
{
pw->pw_history = pw->pw_history->plPrev;
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
break;
}
}
else if (pw->pw_histail)
{
pw->pw_history = pw->pw_histail;
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
break;
}
SetWindowText(pw->hEdit, pw->pw_history->pchLine);
break;
case DOWN_HIT:
if (pw->pw_history)
{
if (pw->pw_history->plNext)
{
pw->pw_history = pw->pw_history->plNext;
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
break;
}
}
else if (pw->pw_hishead)
{
pw->pw_history = pw->pw_hishead;
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
break;
}
SetWindowText(pw->hEdit, pw->pw_history->pchLine);
break;
}
return DefWindowProc(hWnd, wMsg, wParam, lParam);
}
#pragma argsused
int
window_open( char const *pchPath,
int iMode,
int iAccess)
{
HWND hWnd;
HMENU hmenuSys;
if (!bRegistered)
{
WNDCLASS wc;
wc.style = CS_GLOBALCLASS |
CS_HREDRAW |
CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(struct per_window *);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, "TKERN_ICO");
wc.hCursor = (HCURSOR) IDC_IBEAM;
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = "Troy's Kernel Window";
RegisterClass(&wc);
iDevice = get_device_number("window");
}
hWnd = CreateWindow( "Troy's Kernel Window",
pchPath,
WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
0,
0,
hInstance,
0
);
if (!hWnd)
{
nError = ENOMEM;
return -1;
}
else
{
LockManager();
hmenuSys = GetSystemMenu(hWnd, FALSE);
AppendMenu(hmenuSys, MF_SEPARATOR, 0, 0);
AppendMenu(hmenuSys, MF_STRING, SC_COPY, "C&opy");
AppendMenu(hmenuSys, MF_STRING, SC_PASTE, "&Paste");
AppendMenu(hmenuSys, MF_STRING, SC_COPYPASTE, "Cop&y and Paste");
EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
ShowWindow(hWnd, SW_SHOW);
return (int) hWnd;
}
}
static void
add_to_line( struct line *pl,
char const *pchBuffer,
int nBytes)
{
char *pchString;
if (!nBytes)
return;
pchString = (char *) malloc(nBytes +
(pl->pchLine ? strlen(pl->pchLine) : 0) + 1);
if (pl->pchLine)
strcpy(pchString, pl->pchLine);
else
*pchString = 0;
pchString[strlen(pchString) + nBytes] = 0;
memcpy(pchString + strlen(pchString), pchBuffer, nBytes);
if (pl->pchLine)
free(pl->pchLine);
pl->pchLine = pchString;
}
int
window_write( int id,
char const *pchBuffer,
int nBytes)
{
HWND hWnd = (HWND) id;
struct per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
int nLines = 0;
char *pchNewLine;
char const *c = pchBuffer;
struct line *plTemp;
int nLeft = nBytes;
RECT rcRedraw;
if (!nBytes)
return 0;
while (nLeft--)
{
if (*c++ == '\n')
{
add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer - 1);
plTemp = (struct line *) malloc(sizeof(struct line));
plTemp->pchLine = 0;
plTemp->plNext = 0;
plTemp->plPrev = pw->pw_tail;
pw->pw_tail->plNext = plTemp;
pw->pw_tail = plTemp;
pchBuffer = c;
nLines++;
}
}
if (c != pchBuffer)
add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer);
GetClientRect(hWnd, &rcRedraw);
rcRedraw.top = rcRedraw.bottom - pw->cyChar - pw->cyChar / 5 * 2;
InvalidateRect(hWnd, &rcRedraw, TRUE);
if (nLines)
{
/* Rather than scrolling every line, which
* is somewhat slow, scroll after some
* number of lines as set by the user.
* This is processed via a posted message,
* so once an app starts flushing messages,
* any outstanding scrolling should be
* processed.
*/
if (!pw->nScrollPos)
{
pw->nUnscrolledLines += nLines;
if (pw->nUnscrolledLines >= pw->nScrollLines)
FlushMessages();
}
MoveMark(pw, nLines);
pw->nLines += nLines;
while (pw->nLines > pw->nLinesMax)
{
plTemp = pw->pw_head;
pw->pw_head = plTemp->plNext;
if (plTemp->pchLine)
free(plTemp->pchLine);
free(plTemp);
pw->pw_head->plPrev = 0;
pw->nLines--;
}
if (pw->nScrollPos)
pw->nScrollPos += nLines;
SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
SetScrollPos(hWnd, SB_VERT, pw->nLines - pw->nScrollPos, TRUE);
}
return nBytes;
}
int
window_read( int id,
char *pchBuffer,
int nBytes)
{
HWND hWnd = (HWND) id;
struct per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
struct line *pl;
char *pchNewLine;
int iLen;
if (!pw->pw_inhead)
return FR_NOTREADY;
pl = pw->pw_inhead;
iLen = strlen(pl->pchLine);
if (iLen >= nBytes)
{
memcpy(pchBuffer, pl->pchLine, nBytes);
pchNewLine = (char *) malloc(iLen + 1 - nBytes);
memcpy(pchNewLine, pl->pchLine + nBytes, iLen + 1 - nBytes);
free(pl->pchLine);
pl->pchLine = pchNewLine;
}
else
{
memcpy(pchBuffer, pl->pchLine, iLen);
pchBuffer[iLen] = '\n';
pw->pw_inhead = pl->plNext;
if (!pl->plNext)
pw->pw_intail = 0;
free(pl->pchLine);
free(pl);
nBytes = iLen + 1;
}
window_write(id, pchBuffer, nBytes);
return nBytes;
}
int
window_close( int id)
{
HWND hWnd = (HWND) id;
struct per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
HMENU hmenuSys = GetSystemMenu(hWnd, TRUE);
char *pchOldText;
char *pchNewText;
int nTextLen;
EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
pw->bProgramClosed = TRUE;
nTextLen = GetWindowTextLength(hWnd);
pchOldText = (char *) malloc(nTextLen + 1);
GetWindowText(hWnd, pchOldText, nTextLen + 1);
pchOldText[nTextLen] = 0;
pchNewText = malloc(nTextLen + 12);
strcpy(pchNewText, "(Inactive ");
strcat(pchNewText, pchOldText);
strcat(pchNewText, ")");
free(pchOldText);
SetWindowText(hWnd, pchNewText);
free(pchNewText);
return 0;
}
static int
window_destroy(HWND hWnd)
{
struct line *pl, *plNext;
struct per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
DestroyWindow(hWnd);
for (pl = pw->pw_head; pl; pl = plNext)
{
plNext = pl->plNext;
if (pl->pchLine)
free(pl->pchLine);
free(pl);
}
for (pl = pw->pw_hishead; pl; pl = plNext)
{
plNext = pl->plNext;
if (pl->pchLine)
free(pl->pchLine);
free(pl);
}
for (pl = pw->pw_inhead; pl; pl = plNext)
{
plNext = pl->plNext;
if (pl->pchLine)
free(pl->pchLine);
free(pl);
}
free(pw);
UnlockManager();
return 0;
}
void
CheckLimits( HWND hWnd,
struct per_window *pw)
{
struct line *plTemp;
while (pw->nLines > pw->nLinesMax)
{
plTemp = pw->pw_head;
pw->pw_head = plTemp->plNext;
if (plTemp->pchLine)
free(plTemp->pchLine);
free(plTemp);
pw->pw_head->plPrev = 0;
pw->nLines--;
}
while (pw->nHistory > pw->nHistMax)
{
plTemp = pw->pw_hishead;
pw->pw_hishead = plTemp->plNext;
pw->pw_hishead->plPrev = 0;
if (plTemp->pchLine)
free(plTemp->pchLine);
free(plTemp);
pw->nHistory--;
}
pw->pw_history = 0;
SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
}
void
GetWindowSize( HWND hWnd,
struct per_window *pw,
struct winsize *wsize)
{
RECT rcWindow;
GetClientRect(hWnd, &rcWindow);
wsize->ws_xpixel = rcWindow.right;
wsize->ws_ypixel = rcWindow.bottom;
wsize->ws_col = rcWindow.right / pw->cxChar;
wsize->ws_row = (rcWindow.bottom - pw->cyChar / 5 * 2) / pw->cyChar;
}
void
SetWindowSize( HWND hWnd,
struct per_window *pw,
struct winsize *wsize)
{
RECT rcClient;
RECT rcWindow;
int xExtra;
int yExtra;
int xSize;
int ySize;
GetClientRect(hWnd, &rcClient);
GetWindowRect(hWnd, &rcWindow);
xExtra = (rcWindow.right - rcWindow.left) - rcClient.right;
yExtra = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
if (wsize->ws_col)
xSize = wsize->ws_col * pw->cxChar;
else if (wsize->ws_xpixel)
xSize = wsize->ws_xpixel;
else
xSize = rcClient.right;
if (wsize->ws_row)
ySize = wsize->ws_row * pw->cyChar + pw->cyChar / 5 * 2;
else if (wsize->ws_ypixel)
ySize = wsize->ws_ypixel;
else
ySize = rcClient.bottom;
MoveWindow(hWnd,
rcWindow.left,
rcWindow.top,
xSize + xExtra,
ySize + yExtra,
TRUE);
}
int
window_ioctl( int fd,
struct tk_ioctl *tki)
{
HWND hWnd = (HWND) fd;
struct wio_parms * const wiop = (struct wio_parms *) tki->achBuffer;
struct per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
switch(tki->nIOCtl)
{
case WIOCGETHANDLE:
return fd;
case WIOCGETNAME:
return GetWindowText(hWnd, tki->achBuffer, tki->nSize);
case WIOCSETNAME:
SetWindowText(hWnd, tki->achBuffer);
return 0;
case WIOCGETPARMS:
wiop->wiop_display_lines = pw->nLinesMax;
wiop->wiop_history_lines = pw->nHistMax;
wiop->wiop_scroll_lines = pw->nScrollLines;
return 0;
case WIOCSETPARMS:
pw->nLinesMax = wiop->wiop_display_lines;
pw->nHistMax = wiop->wiop_history_lines;
pw->nScrollLines = wiop->wiop_scroll_lines;
CheckLimits(hWnd, pw);
return 0;
case TIOCGWINSZ:
GetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
return 0;
case TIOCSWINSZ:
SetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
return 0;
default:
nError = EINVAL;
return -1;
}
}